package com.wish.util;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.SearchResultMapper;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * es的工具类型
 *
 * @author
 */
public class EsUtils {

	private EsUtils() {

	}

	/**
	 * 数据保存/更新的操作
	 *
	 * @param elasticsearchTemplate 操作的模板对象
	 * @param object                保存的实体对象
	 * @param id                    实体对象对应的id值
	 * @throws Exception
	 */
	public static void save(ElasticsearchTemplate elasticsearchTemplate, Object object, String id) throws Exception {
		IndexQuery query = new IndexQueryBuilder().withObject(object).withId(id).build();
		elasticsearchTemplate.index(query);
	}

	/**
	 * 删除数据操作
	 *
	 * @param elasticsearchTemplate 操作的模板对象
	 * @param clazz                 实体对象的clazz类型
	 * @param ids                   要删除的数组id集合
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static void delete(ElasticsearchTemplate elasticsearchTemplate, Class clazz, String ids[]) throws Exception {
		for (String id : ids) {
			elasticsearchTemplate.delete(clazz, id);
		}
	}

	/**
	 * 查询数据操作
	 *
	 * @param elasticsearchTemplate 操作模板对象
	 * @param clazz                 操作实体类类型
	 * @param pageNum               当前页
	 * @param pageSize              每页显示的记录数
	 * @param direction             排序的方式
	 * @param sortFields            排序的字段
	 * @param value                 查询的内容
	 * @param fields                查询的字段
	 * @param field                 权重的字段
	 * @param boost                 权重的值
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static PageInfo search(ElasticsearchTemplate elasticsearchTemplate, Class clazz, Integer pageNum,
								  Integer pageSize, String direction, String sortFields, String value, String[] fields, String field,
								  Float boost) {
		// 设置分页
		PageRequest pageable = null;
		// 加入排序的判断
		if ("asc".equals(direction)) {
			pageable = PageRequest.of(pageNum - 1, pageSize, Sort.by(Direction.ASC, sortFields));
		} else {
			pageable = PageRequest.of(pageNum - 1, pageSize, Sort.by(Direction.DESC, sortFields));
		}

		// 构建查询条件
		MultiMatchQueryBuilder queryBuilder = null;
		SearchQuery searchQuery = null;
		AggregatedPage page = null;

		if (value != null && !"".equals(value)) {

			queryBuilder = new MultiMatchQueryBuilder(value, fields);

			if (field != null) {
				// 权重的问题
				queryBuilder.field(field, boost);
			}

			// 创建高亮字段值
			HighlightBuilder.Field highlightFields[] = new HighlightBuilder.Field[fields.length];
			// 设置字段前后缀
			for (int i = 0; i < highlightFields.length; i++) {
				highlightFields[i] = new HighlightBuilder.Field(fields[i]).preTags("<font color='blue'>")
						.postTags("</font>");
			}
			// 创建查询条件对象
			searchQuery = new NativeSearchQueryBuilder().withPageable(pageable).withQuery(queryBuilder)
					.withHighlightFields(highlightFields).build();

			// 执行查询效果
			page = elasticsearchTemplate.queryForPage(searchQuery, clazz, new SearchResultMapper() {

				@Override
				public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {

					List<T> list = new ArrayList<>();

					// 命中数据
					SearchHits hits = response.getHits();
					long totalHits = hits.getTotalHits();

					// 命中的数据
					SearchHit[] hits2 = hits.getHits();
					for (SearchHit hit : hits2) {
						// 获取原数据的json数据
						String sourceAsString = hit.getSourceAsString();
						// json转换实体对象
						T entity = JSON.parseObject(sourceAsString, clazz);
						// 获取高亮字段值
						Map<String, HighlightField> highlightFields2 = hit.getHighlightFields();
						try {
							for (int i = 0; i < fields.length; i++) {
								// 获取高亮的字段
								HighlightField highlightField = highlightFields2.get(fields[i]);
								if (highlightField!= null) {
									// 获取高亮字段的内容数据
									String value_hight = highlightField.getFragments()[0].toString();
									// 反射获取的字段
									Field field = clazz.getDeclaredField(fields[i]);
									// 暴力反射
									field.setAccessible(true);
									// 设置地段对象的value值
									field.set(entity, value_hight);
								}
							}

						} catch (Exception e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}

						list.add(entity);
					}

					return new AggregatedPageImpl<>(list, pageable, totalHits);
				}

				@Override
				public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
					return null;
				}
			});

		} else {
			// 没有查询条件的的时候，获取es中的全部数据 分页获取
			searchQuery = new NativeSearchQueryBuilder().withPageable(pageable).build();
			page = elasticsearchTemplate.queryForPage(searchQuery, clazz);
		}

		// Mybatis中的分页对象
		Page page_list = new Page<>(pageNum, pageSize);
		// 加入集合
		page_list.addAll(page.getContent());
		// 设置总记录数
		page_list.setTotal(page.getTotalElements());
		// 转换成mybatis中的pageInfo对象
		PageInfo pageInfo = new PageInfo<>(page_list);

		// 返回值
		return pageInfo;
	}

}
